# 指纹特征提取
import cv2
import numpy as np
from skimage.morphology import thin


def fingerprint_preprocessing(image_path):
    """改进的指纹图像预处理"""
    # 读取图像
    image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
    if image is None:
        raise ValueError("无法读取图像，请检查路径！")

    # 中值滤波去噪
    denoised = cv2.medianBlur(image, 3)

    # 自适应阈值二值化
    binary = cv2.adaptiveThreshold(
        denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
        cv2.THRESH_BINARY_INV, 11, 2
    )

    # 形态学操作增强脊线
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
    enhanced = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)

    # 细化处理
    skeleton = thin(enhanced // 255).astype(np.uint8)

    return skeleton


def minutiae_extraction(skeleton):
    """使用交叉数法提取特征点"""
    # 创建标记图像
    marked = cv2.cvtColor((skeleton * 255).astype(np.uint8), cv2.COLOR_GRAY2BGR)
    endpoints = []
    bifurcations = []

    # 计算交叉数（Crossing Number）
    kernel = np.array([[1, 1, 1],
                       [1, 10, 1],
                       [1, 1, 1]], dtype=np.uint8)

    # 使用卷积计算邻域和
    filtered = cv2.filter2D(skeleton, -1, kernel)

    # 提取特征点
    y, x = np.where(skeleton > 0)
    for i, j in zip(y, x):
        cn = filtered[i, j] - 10  # 减去中心点值
        if cn == 1:  # 端点
            endpoints.append((j, i))
            cv2.circle(marked, (j, i), 3, (0, 0, 255), -1)  # 红色
        elif cn >= 3:  # 分叉点
            bifurcations.append((j, i))
            cv2.circle(marked, (j, i), 3, (0, 255, 0), -1)  # 绿色

    print(f"端点数量: {len(endpoints)}, 分叉点数量: {len(bifurcations)}")
    return marked, endpoints + bifurcations


def main():
    image_path = "2.jpg"  # 替换为您的指纹图像路径

    try:
        # 图像预处理
        skeleton = fingerprint_preprocessing(image_path)
        print("指纹图像预处理完成。")

        # 特征提取
        marked_image, coords = minutiae_extraction(skeleton)
        print(f"提取到的特征点总数: {len(coords)}")

        # 显示结果
        cv2.imshow("Skeleton", skeleton * 255)
        cv2.imshow("Minutiae Points", marked_image)
        cv2.waitKey(0)
        cv2.destroyAllWindows()

    except Exception as e:
        print(f"发生错误: {str(e)}")


if __name__ == "__main__":
    main()
